home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / DeveloperLabs / Lab2 / Solution / CompositeView.m < prev    next >
Text File  |  1995-06-12  |  8KB  |  283 lines

  1. // CompositeView implements a view with three horizontal, equal-sized areas.
  2. // The left-most area is the "source," the middle area is the "destination,"
  3. // and the right-most area is the "result." CompositeView assures that the
  4. // contents of the result area is always generated by compositing the other
  5. // two areas using the compositing mode set in the setOperator: method.
  6. // It is also possible to change the contents, color, and alpha of the
  7. // source and destination areas; see the methods setSourceGray:, 
  8. // setSourceAlpha:, etc.
  9.  
  10. // CompositeView written by Bruce Blumberg and Ali Ozer, NeXT Developer Support
  11.  
  12. #import "CompositeView.h"
  13.  
  14. #import <appkit/Bitmap.h>
  15. #import <appkit/Control.h>
  16. #import <appkit/Matrix.h>
  17. #import <appkit/Window.h>
  18.  
  19. #import <dpsclient/wraps.h>
  20.  
  21. @implementation CompositeView
  22.  
  23. // The possible draw modes for the source.
  24.  
  25. #define TRIANGLE 0
  26. #define CIRCLE   1
  27. #define DIAMOND  2
  28. #define HEART    3
  29. #define FLOWER   4
  30.  
  31. // newFrame creates the view, initializes the rectangles that define the
  32. // three areas described above, and creates the bitmaps used for rendering the
  33. // source and destination bitmaps.
  34.  
  35. +newFrame:(const NXRect *)tF
  36. {
  37.     // Create the view
  38.     self = [super newFrame:tF];
  39.  
  40.     // Make rectangles for source, destination and result
  41.     sRect = bounds;
  42.     sRect.size.width /= 3.0;
  43.     dRect = sRect;
  44.     dRect.origin.x = sRect.size.width;
  45.     rRect = dRect;
  46.     rRect.origin.x = dRect.origin.x + dRect.size.width;
  47.  
  48.     // Create bitmap for source image. Bitmaps are flipped by default;
  49.     // make sure we make ours not-flipped.
  50.  
  51.     source = [Bitmap newSize:sRect.size.width :sRect.size.height
  52.             type:NX_UNIQUEBITMAP];
  53.     [source setFlip:NO];
  54.     
  55.     // Now do the same for the destination...
  56.  
  57.     destination = [Bitmap newSize:dRect.size.width :dRect.size.height
  58.             type:NX_UNIQUEBITMAP];
  59.     [destination setFlip:NO];
  60.  
  61.     // Set the default operator and source picture. Also set default 
  62.     // gray and alpha values. You will of course have to make sure
  63.     // the sliders in your Interface Builder window have the same values.
  64.     // (This is a problem; can you see a way to fix it?)
  65.  
  66.     operator = NX_COPY;
  67.     sourcePicture = TRIANGLE;
  68.     sourceGray = 0.333; // dark gray
  69.     destGray = 0.666;   // light gray
  70.     sourceAlpha = 1.0;  // opaque
  71.     destAlpha = 1.0;    // opaque
  72.  
  73.     // Create the bitmap images using the initial values set above
  74.  
  75.     [self drawSource];
  76.     [self drawDestination];
  77.  
  78.     return self;
  79. }
  80.  
  81. // drawSource creates the source image in the source bitmap. Note that
  82. // drawSource does not render in the view; it renders in the bitmap only.
  83.  
  84. -drawSource
  85. {    
  86.     [source lockFocus];
  87.     PScompositerect (0.0, 0.0, sRect.size.width, sRect.size.height, NX_CLEAR);
  88.     PSsetgray(sourceGray);
  89.     PSsetalpha(sourceAlpha);
  90.     PSnewpath();
  91.     switch (sourcePicture) {
  92.     case TRIANGLE: 
  93.          PSmoveto (0.0, 0.0);
  94.         PSlineto (0.0, sRect.size.height);
  95.         PSlineto (sRect.size.width, sRect.size.height);
  96.         break;
  97.     case CIRCLE:
  98.         PSscale (sRect.size.width, sRect.size.height);
  99.         PSarc (0.5, 0.5, 0.4, 0.0, 360.0);  // diameter is 80% of area
  100.          break;
  101.     case DIAMOND:
  102.          PSmoveto (0.0, sRect.size.height / 2.0);
  103.         PSlineto (sRect.size.width / 2.0, 0.0);
  104.         PSlineto (sRect.size.width, sRect.size.height / 2.0);
  105.         PSlineto (sRect.size.width / 2.0, sRect.size.height);
  106.         break;
  107.     case HEART:
  108.         PSscale (sRect.size.width, sRect.size.height);
  109.         PSmoveto (0.5, 0.5);
  110.         PScurveto (0.3, 1.0, 0.0, 0.5, 0.5, 0.1);
  111.         PSmoveto (0.5, 0.5);            
  112.         PScurveto (0.7, 1.0, 1.0, 0.5, 0.5, 0.1);  
  113.         break;
  114.     case FLOWER:
  115.         PSscale (sRect.size.width, sRect.size.height);
  116.         PStranslate (0.5, 0.5);
  117.         PSmoveto (0.0, 0.0); 
  118.             {int cnt;
  119.          for (cnt = 0; cnt < 6; cnt++) {
  120.         PSrotate (60.0);
  121.         PScurveto (0.4, 0.5, -0.4, 0.5, 0.0, 0.0);
  122.          }
  123.         }
  124.         break;
  125.     default:
  126.         break;
  127.     }
  128.     PSclosepath();
  129.     PSfill();
  130.     [source unlockFocus];
  131.  
  132.     return self;
  133. }
  134.  
  135. // drawDestination creates the destination image in the destination bitmap. 
  136. // Like drawSource, drawDestination only draws in the bitmap, not the view.
  137.  
  138. -drawDestination
  139. {
  140.     [destination lockFocus];
  141.     PScompositerect (0.0, 0.0, dRect.size.width, dRect.size.height, NX_CLEAR);
  142.     PSsetgray(destGray);
  143.     PSsetalpha(destAlpha);
  144.     PSnewpath();
  145.     PSmoveto(dRect.size.width, 0.0);
  146.     PSlineto(dRect.size.width, dRect.size.height);
  147.     PSlineto(0.0, dRect.size.height);
  148.     PSclosepath();
  149.     PSfill();
  150.     [destination unlockFocus];
  151.     return self;
  152. }
  153.  
  154. // setSourcePicture allows setting the picture to be drawn in the source
  155. // bitmap. Buttons connected to this method should have tags that are 
  156. // set to the various possible pictures (see the "#define"s, above).
  157. //
  158. // After setting the sourcePicture instance variable, setSourcePicture redraws
  159. // the bitmap and updates the view to reflect the new configuration.
  160.  
  161. -setSourcePicture:(id)ctl
  162. {
  163.     sourcePicture = [ctl selectedTag];
  164.     [self drawSource];
  165.     [self display];
  166.     return self;
  167. }
  168.  
  169. // The following four methods set the color or alpha parameters and update
  170. // the source or destination bitmaps and the view to reflect the change.
  171.  
  172. -setSourceGray:(id)ctl
  173. {
  174.     sourceGray = [ctl floatValue];
  175.     [self drawSource];
  176.     [self display];
  177.     return self;
  178. }
  179.  
  180. -setDestGray:(id)ctl
  181. {
  182.     destGray = [ctl floatValue];
  183.     [self drawDestination];
  184.     [self display];
  185.     return self;
  186. }
  187.  
  188. -setSourceAlpha:(id)ctl
  189. {
  190.     sourceAlpha = [ctl floatValue];
  191.     [self drawSource];
  192.     [self display];
  193.     return self;
  194. }
  195.  
  196. -setDestAlpha:(id)ctl
  197. {
  198.     destAlpha = [ctl floatValue];
  199.     [self drawDestination];
  200.     [self display];
  201.     return self;
  202. }
  203.  
  204. // The operator method returns the operator currently in use.
  205.  
  206. -(int)operator {return operator;}
  207.  
  208.  
  209. // setOperator sets the operator to be used in the compositing operations
  210. // and updates the view to reflect the change. Note that setOperator needs
  211. // to be connected to a row of buttons.
  212.  
  213. -setOperator:(id)sender
  214. {    
  215.     char *modeName;
  216.     
  217.     switch ([sender selectedRow]) {
  218.     case 0: operator = NX_COPY;        break;
  219.     case 1: operator = NX_CLEAR;         break;
  220.     case 2: operator = NX_SOVER;         break;
  221.     case 3: operator = NX_DOVER;        break;
  222.     case 4: operator = NX_SIN;         break;
  223.     case 5: operator = NX_DIN;         break;
  224.     case 6: operator = NX_SOUT;        break;
  225.     case 7: operator = NX_DOUT;        break;
  226.     case 8: operator = NX_SATOP;        break; 
  227.     case 9: operator = NX_DATOP;        break;
  228.     case 10: operator = NX_XOR;         break;
  229.     case 11: operator = NX_PLUSD;        break;
  230.     case 12: operator = NX_PLUSL;        break;
  231.     default: break;
  232.     }
  233.     [self speedyDraw];
  234.  
  235.     return self;
  236. }
  237.  
  238.         
  239. // drawSelf:: simply redisplays the contents of the view. The source and
  240. // destination rectangles are updated from the bitmaps while the result
  241. // rectangle is created by compositing the two bitmaps.
  242.  
  243. -drawSelf:(NXRect *)r :(int) count
  244. {
  245.     // Erase the whole view
  246.     NXEraseRect(&bounds);
  247.  
  248.     // Draw the source bitmap and then frame it with black
  249.     [source composite:NX_COPY toPoint:&sRect.origin];
  250.     PSsetgray(NX_BLACK);
  251.     NXFrameRect(&sRect);
  252.  
  253.     // Draw the destination bitmap and frame it with black 
  254.     [destination composite:NX_COPY toPoint:&dRect.origin];
  255.     PSsetgray(NX_BLACK);
  256.     NXFrameRect(&dRect);
  257.  
  258.     // And now create the destination image and frame it with black as well
  259.     [destination composite:NX_COPY toPoint:&rRect.origin];
  260.     [source composite:operator toPoint:&rRect.origin];
  261.     PSsetgray(NX_BLACK);
  262.     NXFrameRect(&rRect);
  263.  
  264.     return self;
  265. }
  266.  
  267. // speedyDraw provides some efficiency in redisplaying the view by assuming
  268. // that the source and the destination rectangles are already in place.
  269.  
  270. -speedyDraw
  271. {
  272.     [self lockFocus];
  273.     NXEraseRect(&rRect);
  274.     [destination composite:NX_COPY toPoint:&rRect.origin];
  275.     [source composite:operator toPoint:&rRect.origin];
  276.     NXFrameRect(&rRect);
  277.     [self unlockFocus];
  278.     [[self window] flushWindow];
  279.  
  280.     return self;
  281. }
  282.  
  283. @end